home *** CD-ROM | disk | FTP | other *** search
- COMMENT *
-
- CLUBware (tm)
-
- BASPRINT - Enhancement to the Basic Interpreter Print statement
-
- Copyright 1984 Rayhawk Automation N.W. Inc
- P.O. Box 1427
- Beaverton, Oregon 97075
- *
-
- SCRDSEG SEGMENT
-
- ASSUME CS:SCRDSEG,DS:NOTHING,ES:NOTHING,SS:STACK
-
- ORIG_INT10 LABEL WORD ; original int 10
- DW 0
- DW 0
- ;______________________________________________________________________________
-
- ; Swap the B4 interrupt used by BASIC to print strings. Swap must be made
- ; after BASIC has been loaded and initialized its environment. Swap takes
- ; place when BASIC clears the screen.
-
-
- ORIG_INTB4 LABEL WORD ; original int b4
- DW 0
- DW 0
-
-
- INTSWAP PROC FAR
-
- CMP AX,0600h ; clear screen request?
- JE DO_SWAP
- JMP DWORD PTR ORIG_INT10 ; pass call to BIOS
-
- DO_SWAP:
- PUSH DS
- PUSH AX
-
- SUB AX,AX ; address low memory
- MOV DS,AX
-
- CLI ; disable interrupts for a moment
-
- ; vector for B4 is at 2D0
-
- ; have we already taken over this interrupt once before?
-
- CMP WORD PTR DS:[02D0h],OFFSET PRINTER
- JE ALREADY_SAVED
-
-
- ; save the original interrupt vector for use by error message reports
-
- MOV AX,WORD PTR DS:[02D0h]
- MOV ORIG_INTB4,AX
- MOV AX,WORD PTR DS:[02D2h]
- MOV ORIG_INTB4+2,AX
-
- ; replace the original interrupt vector to allow us to intercept prints
-
- MOV AX,OFFSET PRINTER
- MOV WORD PTR DS:[02D0h],AX
- MOV AX,SEG PRINTER
- MOV WORD PTR DS:[02D2h],AX
-
- ALREADY_SAVED:
-
- STI
-
- POP AX
- POP DS
- JMP DWORD PTR ORIG_INT10 ; pass clear screen to BIOS now
-
-
-
- INTSWAP ENDP
-
- ;______________________________________________________________________________
-
- COMMENT * PRINTER prints a character string on the screen starting
- at the current cursor position. After the string is
- written to the screen the cursor position is updated
- to just after the string.
-
- To use this routine, INTSWAP must have swapped the interrupt
- vector for intterupt B4 and redirected it to the PRINTER
- subroutine.
-
- The BASPRINT module will take over the INT 10h and make
- this module permanently resident. When the screen is cleared
- by BASIC, INTSWAP will swap INT B4 and point the vector
- to the PRINTER subroutine.
-
- Algorithm:
-
- check context for simple text to screen or possibly something
- more involved that basic should handle
-
- 1) store character count and mark the flag for type of i/o
- 2) load current page from DS:[0049]
- 3) load current position on page from DS:[0056]
- 4) load attribute for string from DS:[004E]
- 5) move character count to CX for use in loop
- 6) load type of crt display from 0000:463
- 7) address the screen segment
- 8) move string to screen while synchronizing
- with horizontal retrace
- 9) update cursor position on screen
- 10) update cursor position in database at DS:[0056]
- 11) leave registers in manner BASIC expects
-
- On entry
- DS:[SI] points to string to write
- DH contains count of characters to write
- DS:[CX] also points to string and must be updated on exit
- DS:[0049] contains the page to which we write
- DS:[004E] contains the attribute for the text
- DS:[0056] contains the current screen location and must
- be updated after print is complete
-
-
- *
- ;______________________________________________________________________________
-
- ; Local data addressable through CS register
-
-
- CHAR_COUNT LABEL BYTE
- DB 0
-
-
- LINE_START LABEL WORD
- DW 0 ; 0
- DW 160 ; 1
- DW 320 ; 2
- DW 480 ; 3
- DW 640 ; 4
- DW 800 ; 5
- DW 960 ; 6
- DW 1120 ; 7
- DW 1280 ; 8
- DW 1440 ; 9
-
- DW 1600 ; 10
- DW 1760 ; 11
- DW 1920 ; 12
- DW 2080 ; 13
- DW 2240 ; 14
- DW 2400 ; 15
- DW 2560 ; 16
- DW 2720 ; 17
- DW 2880 ; 18
- DW 3040 ; 19
- DW 3200 ; 20
- DW 3360 ; 21
- DW 3520 ; 22
- DW 3680 ; 23
- DW 3840 ; 24
-
- PAGE_START LABEL WORD
- DW 0
- DW 4000
- DW 8000
- DW 12000
-
- STARTING_PAGE LABEL WORD
- DW 0
-
- END_OF_PAGE LABEL WORD
- DW 0
-
- STARTING_LINE LABEL WORD
- DW 0
-
- RESIDUAL LABEL BYTE
- DB 0
-
- ROM_SEGMENT LABEL WORD ; basic segment in ROM
- DW 0F600h
-
- LOCAL_FLAG LABEL BYTE
- DB 00000000b
- JUST_BLANKS EQU 00000001b ; basic wants just blanks displayed
-
-
- ;______________________________________________________________________________
-
- COMMENT *
-
- New service routine for interrupt B4
-
- Calls to routine F600:2BA5 generate B4 interrupts.
- These calls come from several places within the BASIC ROM.
- We service calls from two locations: 26CC - call to display a string
- 148D - call to display blanks
- Calls from anywhere else are serviced by the original basic code.
- The two labels corresponding to the two types of calls we service
- are STRING_IO
- REPEAT_BLANKS
- The code labeled BASIC_IO passes the interrupt back to the basic code
- for service.
- *
-
-
- PRINTER PROC FAR
-
- PUSH BP
- MOV BP,SP ; address the stack
-
-
- ; check context for simple text to screen or possibly something
- ; more involved that basic should handle
-
- CMP WORD PTR DS:[04E9h],0
- JNE BASIC_IO
- CMP WORD PTR DS:[071Fh],0
- JNE BASIC_IO
- CMP BYTE PTR DS:[0758h],0
- JNE BASIC_IO
- CMP BYTE PTR DS:[071Bh],0
- JNE BASIC_IO
- CMP BYTE PTR DS:[0029h],50h ; 80 bytes per line?
- JNE BASIC_IO
- CMP BYTE PTR DS:[0056h],25 ; on bottom line of screen?
- JE BASIC_IO ; if so, let basic handle it
- CMP WORD PTR [BP+8],26CCh ; just regular i/o?
- JE STRING_IO
- CMP WORD PTR [BP+8],148Dh ; just repeated blanks?
- JE REPEAT_BLANKS
-
- ; allow original B4 service routine to perform I/O
-
- BASIC_IO:
- POP BP
- JMP DWORD PTR ORIG_INTB4 ; pass control to original B4
-
-
-
- ; ----------
-
-
- ; repeated blanks sent to screen
-
- REPEAT_BLANKS:
-
- PUSH BX ; save registers used
- PUSH DX
- PUSH DI
- PUSH ES
- PUSH CX
-
-
- ; ... 1) store character count and mark the flag for type of i/o
-
- MOV CHAR_COUNT,CH ; save character count
- OR LOCAL_FLAG,JUST_BLANKS
- MOV RESIDUAL,DH ; dh should be untouched
- JMP SETUP_START
-
-
- ; ----------
-
-
- ; write the string for basic
-
- STRING_IO:
-
- PUSH BX ; save registers used,
- PUSH DX
- PUSH DI
- PUSH ES
-
-
-
- ; ... 1) backup to start of string and store character count
-
- DEC SI ; backup to start of string
- MOV CHAR_COUNT,DH ; save character count
- MOV LOCAL_FLAG,0 ; clear the flag for string i/o
- MOV RESIDUAL,1 ; dh to contain 1 on exit
-
-
- ; ... 2) load current page from DS:[0049]
-
- SETUP_START:
- MOV BL,BYTE PTR DS:[0049h] ; load current page
- SUB BH,BH
- SHL BX,1 ; convert to a table offset
- MOV DI,PAGE_START[BX] ; load start of page
- MOV STARTING_PAGE,DI ; save the page
- MOV END_OF_PAGE,DI ; save ending page pointer
- ADD END_OF_PAGE,3840
-
-
-
- ; ... 3) load current position on page from DS:[0056]
-
- MOV DX,WORD PTR DS:[0056h] ; load current position
- DEC DH ; basic counts from 1 instead of 0
- DEC DL ; basic counts from 1 instead of 0
- MOV BL,DL ; load row number
- SHL BX,1 ; two bytes per table entry
- ADD DI,LINE_START[BX] ; add in start of line
- MOV STARTING_LINE,DI ; store this for later
-
-
- MOV DL,DH ; bring down column number
- SUB DH,DH
- ADD DI,DX ; add in column position
- ADD DI,DX ; account for attribute bytes
-
-
-
- ; ... 4) load attribute for string from DS:[004E]
-
- MOV BH,BYTE PTR DS:[004Eh] ; load attribute for string
-
-
-
- ; ... 5) move character count to CX for use in loop
-
- SUB CH,CH ; clear upper byte
- MOV CL,CHAR_COUNT ; load the character count
-
-
-
- ; ... 6) load type of crt display from 0000:463
-
- SUB AX,AX ; address system memory
- MOV ES,AX
-
- MOV DX,WORD PTR ES:[463h] ; load address of display adapter
- ADD DX,6 ; address crt status port
-
-
- ; ... 7) address the screen segment
-
- MOV AX,0B000h ; screen seg for monochrome card
- CMP DX,03DAh ; is this a graphic card?
- JNE MONOCHROME
-
- MOV AX,0B800h ; load screen seg for graphic card
-
- MONOCHROME:
-
- MOV ES,AX ; address the screen buffer
-
-
-
- ; ... 8) move string to screen while synchronizing
- ; with horizontal retrace
-
- TEST LOCAL_FLAG,JUST_BLANKS
- JZ DISPLAY_LOOP
-
- MOV BL,20h ; load a blank
- BLANK_LOOP:
- CALL DISPLAY_CHAR ; display a line of blanks for basic
- LOOP BLANK_LOOP
- JMP UPDATE_POSITION
-
-
- DISPLAY_LOOP:
- LODSB ; load next character
-
- CMP AL,20h ; special character?
- JGE NOT_SPECIAL
- CALL SPECIAL
- JZ ANOTHER_CHAR ; if flag set, go for another character
-
- NOT_SPECIAL:
-
- MOV BL,AL
-
- CLI
- HSYNC_WAIT1:
- IN AL,DX ; check for horizontal retrace
- TEST AL,1
- JNZ HSYNC_WAIT1 ; wait for retrace
- HSYNC_WAIT2:
- IN AL,DX ; check for horizontal retrace
- TEST AL,1
- JZ HSYNC_WAIT2 ; wait for retrace
-
- MOV AX,BX
- STOSW ; store character and attribute
-
- ANOTHER_CHAR:
- STI
-
- CMP DI,END_OF_PAGE
- JL NOT_SCROLLED
-
- MOV AL,0Dh ; force a carriage return
- CALL SPECIAL
-
- NOT_SCROLLED:
-
- LOOP DISPLAY_LOOP ; repeat cx times
-
-
-
- ; ... 9) update cursor position on screen
-
-
- UPDATE_POSITION:
- MOV AX,DI
- SUB AX,STARTING_PAGE
- SHR AX,1 ; eliminate attribute bytes
- SUB DX,DX
- MOV BX,80 ; divide by bytes per line
- DIV BX ; quotient in AL (ROW)
- ; remainder in DL (COLUMN)
- MOV DH,AL
- MOV BH,BYTE PTR DS:[0049h] ; load page number
- MOV AH,2 ; request new position
- INT 10h
-
-
- ; ... 10) update cursor position in database at DS:[0056]
-
- XCHG DH,DL ; basic likes this reversed
- INC DH ; basic counts from 1 instead of 0
- INC DL ; basic counts from 1 instead of 0
- MOV WORD PTR DS:[0056h],DX
-
-
- ; ... 11) leave registers in manner BASIC expects
-
-
- TEST LOCAL_FLAG,JUST_BLANKS
- JZ STRING_DISPLAYED
-
- POP CX ; restore original blank count
- MOV CH,1 ; allow basic to decrement this to 0
- JMP RESTORE_REGS
-
-
- STRING_DISPLAYED: ; for a string
- MOV CX,SI ; CX must point to last character
- DEC CX
-
-
- RESTORE_REGS:
- POP ES
- POP DI
- POP DX
-
- MOV DH,RESIDUAL ; let decrement instr take this to zero
- ; inside basic interpreter
- POP BX
- POP BP
-
-
- ADD SP,4 ; throw away offset and code segment
- ; from INT B4
- POPF ; restore flags from interrupt
-
- POP AX ; throw away near call on stack
- PUSH ROM_SEGMENT ; and convert to a far call
- PUSH AX
- MOV AL,20h ; leave a character in AL for basic
- ; to compare against a CR (0Dh)
- RET ; return to ROM
-
-
- PRINTER ENDP
-
- ;______________________________________________________________________________
-
- ; subroutine to handle special control characters
-
- SPECIAL PROC NEAR
-
- ; ----------
-
- CMP AL,0Ah ; line feed?
- JE NEW_LINE
-
-
- ; ----------
-
- CMP AL,0Bh ; home?
- JNE NOT_HOME
- MOV DI,STARTING_PAGE ; start over at top of screen
- MOV STARTING_LINE,DI
- SUB AL,AL
- RET
-
- NOT_HOME:
-
- ; ----------
-
- CMP AL,0Ch ; clear screen?
- JNE NOT_CLEAR
- MOV DI,STARTING_PAGE
- MOV STARTING_LINE,DI
- MOV AL,0 ; clear whole window
- JMP SHORT SCROLL_SCREEN
-
-
- NOT_CLEAR:
-
- ; ----------
-
- CMP AL,0Dh ; carriage return?
- JNE NOT_CR
-
- NEW_LINE:
- MOV DI,STARTING_LINE
- ADD DI,160
- JMP SHORT TEST_RIGHT
-
- NOT_CR:
-
- ; ----------
-
- CMP AL,1Ch ; move right?
- JNE NOT_RIGHT
- ADD DI,2
- JMP SHORT TEST_RIGHT
-
- NOT_RIGHT:
-
- ; ----------
-
- CMP AL,1Dh ; move left?
- JNE NOT_LEFT
- SUB DI,2
- JMP SHORT TEST_LEFT
-
- NOT_LEFT:
-
- ; ----------
-
- CMP AL,1Eh ; move up?
- JNE NOT_UP
-
- SUB DI,160
- JMP SHORT TEST_LEFT
-
- NOT_UP:
-
- ; ----------
-
- CMP AL,1Fh ; move down?
- JNE NOT_DOWN
-
- ADD DI,160
- JMP SHORT TEST_RIGHT
-
- NOT_DOWN:
- JMP SHORT TEST_FOR_TAB
-
- ; ----------
-
- TEST_RIGHT:
- MOV AX,DI ; are we past line 24?
- SUB AX,STARTING_PAGE
- CMP AX,3840
- JL VALID_RIGHT
- MOV DI,STARTING_PAGE ; back at start of last line
- ADD DI,3680
- MOV STARTING_LINE,DI
-
- MOV AL,1 ; scroll one line
- JMP SHORT SCROLL_SCREEN
-
- VALID_RIGHT:
- SUB AL,AL
- RET
-
- ; ----------
-
- SCROLL_SCREEN:
- PUSH CX
- MOV CX,0 ; start in upper left corner
- PUSH DX
- MOV DX,174Fh ; end in lower right, one line up
- MOV AH,6
- PUSHF ; simulate an INT 10
- CALL DWORD PTR ORIG_INT10
- POP DX
- POP CX
- SUB AL,AL
- RET
-
- ; ----------
-
- TEST_LEFT:
- CMP DI,STARTING_PAGE
- JGE VALID_LEFT
-
- MOV DI,STARTING_PAGE
-
- VALID_LEFT:
- SUB AL,AL
- RET
-
- ; ----------
-
- TEST_FOR_TAB:
-
- CMP AL,09h ; tab?
- JNE NOT_TAB
-
- PUSH CX
- PUSH DX
- MOV AX,DI
- SUB AX,STARTING_LINE
- SHR AX,1 ; discount attribute bytes
- SUB DX,DX
- MOV CX,8
- DIV CX
- MOV CX,8 ; tab positions are every 8 charactes
- SUB CX,DX ; subtract off remainder
- MOV BL,' ' ; write some blanks
- POP DX
- TAB_LOOP:
- CALL DISPLAY_CHAR
- LOOP TAB_LOOP
-
- POP CX
- SUB AL,AL
- RET
-
- NOT_TAB:
-
- ; ----------
-
- CMP AL,08h ; backspace?
- JNE NOT_BACKSPACE
-
- CMP DI,STARTING_LINE
- JE AT_START
- SUB DI,2 ; back up a space
-
- AT_START:
- MOV BL,' ' ; write a blank
- CALL DISPLAY_CHAR
-
- SUB DI,2 ; back up a space
- SUB AL,AL
- RET
-
- NOT_BACKSPACE:
-
- ; ----------
-
- MOV AH,2
- SUB AH,1 ; set flag to display the char
- RET
-
- SPECIAL ENDP
-
- ;______________________________________________________________________________
-
- ; routine to display a character in BL - used only for special characters
- ; attribute is in BH
-
-
- DISPLAY_CHAR PROC NEAR
-
- CLI
- HSYNC_WAIT3:
- IN AL,DX ; check for horizontal retrace
- TEST AL,1
- JNZ HSYNC_WAIT3 ; wait for retrace
- HSYNC_WAIT4:
- IN AL,DX ; check for horizontal retrace
- TEST AL,1
- JZ HSYNC_WAIT4 ; wait for retrace
-
- MOV AX,BX
- STOSW ; store character and attribute
-
- STI
- RET
-
- DISPLAY_CHAR ENDP
-
-
- ;______________________________________________________________________________
-
- LASTADDR LABEL BYTE
-
- COPYRIGHT LABEL BYTE
- DB 10,13
- DB ' CLUBware (tm)',10,13,10,13
- DB 'BASPRINT - Enhancement to the Basic Interpreter Print statement'
- DB 10,13,10,13
- DB ' Copyright 1984 Rayhawk Automation N.W. Inc',10,13
- DB ' P.O. Box 1427',10,13
- DB ' Beaverton, Oregon 97075',10,13,'$'
-
- ;______________________________________________________________________________
-
- BASPRINT PROC FAR
-
-
- PUSH DS ; Push addr of Program Segment Prefix
- SUB AX,AX ; Zero AX
- PUSH AX ; Push zero onto stack
- ; (offset of INT 20 within PSP)
-
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | take over the INT 10h |
- ; | interrupt if not already done |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- MOV DS,AX ; address low memory
- LDS BX,DWORD PTR DS:[02D0h] ; load interrupt vector for int B4
-
- MOV AX,WORD PTR PRINTER
- CMP AX,WORD PTR DS:[BX]
- JNE NOT_HERE_YET
- MOV AX,WORD PTR PRINTER+2
- CMP AX,WORD PTR DS:[BX+2]
- JNE NOT_HERE_YET
- MOV AX,WORD PTR PRINTER+4
- CMP AX,WORD PTR DS:[BX+4]
- JNE NOT_HERE_YET
- MOV AX,WORD PTR PRINTER+6
- CMP AX,WORD PTR DS:[BX+6]
- JNE NOT_HERE_YET
-
- JMP ALREADY_RESIDENT
-
- NOT_HERE_YET:
- SUB AX,AX
- MOV DS,AX
- MOV AX,WORD PTR DS:[40h] ; save original int10
- MOV ORIG_INT10,AX
- MOV AX,WORD PTR DS:[42h]
- MOV ORIG_INT10+2,AX
-
- MOV AX,SEG BASPRINT
- MOV DS,AX
- MOV DX,OFFSET INTSWAP ; Load offset of interrupt service mod
- MOV AX,2510h ; Prepare for DOS service call type 25
- ; to establish service for INT 10
- INT 21h ; Ask DOS to establish service
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | issue copyright message |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- MOV DX,OFFSET COPYRIGHT
- MOV AH,9
- INT 21h
-
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | modify INT 20 into INT 27 in the |
- ; | program segment prefix |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- MOV BYTE PTR ES:[01],27h ; Change INT 20h to INT 27h
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | 6) load address of ending tag into DX |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- MOV AX,SEG LASTADDR
- SUB AX,SEG BASPRINT
- MOV CL,4 ; prepare for 4 bit shift
- SHL AX,CL ; shift up (convert from seg to abs)
- ADD AX,OFFSET LASTADDR ; add address of bottom location
- ADD AX,0103h ; Pad offset because DOS measures
- ; offset relative to Program
- ; Segment Prefix
- MOV DX,AX ; leave where DOS will find it
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | 7) use RET FAR to return to DOS and |
- ; | leave service routine resident |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- ALREADY_RESIDENT:
-
- RET
-
- BASPRINT ENDP
-
- SCRDSEG ENDS
-
- ;______________________________________________________________________________
-
-
- STACK SEGMENT PARA STACK 'STACK'
- DB 24 DUP('STACK***')
- TOPSTACK DB 0
- STACK ENDS
-
- END BASPRINT